"""
策略管理器 - 负责策略的创建、销毁和事件分发
【优化重点】完全基于 strategy_id 进行策略控制，避免 stock_code 依赖
"""
import logging
import asyncio
from typing import Dict, Any, List, Optional, Type
from collections import defaultdict

from strategies.grid_trading_strategy import GridTradingStrategy
from .base_strategy import BaseStrategy
from strategies import TrendStrategy, MeanReversionStrategy

logger = logging.getLogger("StrategyManager")

class StrategyManager:
    """策略生命周期和事件管理器"""
    
    _instance = None
    
    def __new__(cls):
        """单例模式"""
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance
    
    def __init__(self):
        """重构初始化 - 明确数据结构"""
        if hasattr(self, '_initialized') and self._initialized:
            return
        
        # {strategy_id: strategy_instance}
        self._strategies: Dict[str, BaseStrategy] = {}
        # {strategy_id: [stock_code1, stock_code2...]}
        self._strategy_subscriptions: Dict[str, List[str]] = {}
        # {stock_code: [strategy_id1, strategy_id2...]}
        self._stock_subscribers: Dict[str, List[str]] = defaultdict(list)
        
        # 策略类型映射
        self._strategy_types: Dict[str, Type[BaseStrategy]] = {
            "trend": TrendStrategy,
            "mean_reversion": MeanReversionStrategy,
            "grid_trading": GridTradingStrategy
        }
        
        self._initialized = True
        logger.info("🔄 策略管理器初始化完成 (精确策略控制版)")
    
    def get_strategy_class(self, strategy_type: str) -> Type[BaseStrategy]:
        """获取策略类"""
        strategy_class = self._strategy_types.get(strategy_type.lower())
        if not strategy_class:
            available = list(self._strategy_types.keys())
            raise ValueError(f"不支持的策略类型: {strategy_type}。可用类型: {available}")
        return strategy_class
    
    async def add_strategy(self, strategy_type: str, params: Dict[str, Any], strategy_id: Optional[str] = None) -> str:
        """
        创建并启动新策略
        
        参数:
        - strategy_type: 策略类型，如 "trend"
        - params: 策略参数
        - strategy_id: 可选的策略ID，如果为None则自动生成
        
        返回:
        - 策略ID
        """
        # 1. 获取策略类
        strategy_class = self.get_strategy_class(strategy_type)
        
        # 2. 创建策略实例
        strategy = strategy_class(strategy_id=strategy_id, params=params)
        
        # 3. 启动策略
        await strategy.start()
        
        # 4. 添加到管理器
        self._strategies[strategy.strategy_id] = strategy
        
        logger.info(f"✅ 策略已创建并启动: {strategy_type} / {strategy.strategy_id}")
        return strategy.strategy_id
    
    async def remove_strategy(self, strategy_id: str):
        """
        【精确控制】停止并移除指定策略 - 完全基于 strategy_id
        
        优化点:
        1. 不再依赖 stock_code，直接通过 strategy_id 定位
        2. 自动清理该策略的所有订阅
        3. 保持策略状态隔离，不影响其他策略
        """
        strategy = self._strategies.pop(strategy_id, None)
        if not strategy:
            logger.warning(f"⚠️ 尝试移除不存在的策略: {strategy_id}")
            return
        
        # 1. 停止策略
        await strategy.stop()
        
        # 2. 【关键优化】清理该策略的所有订阅 - 基于 strategy_id
        if strategy_id in self._strategy_subscriptions:
            for stock_code in list(self._strategy_subscriptions[strategy_id]):
                await self.remove_subscription(stock_code, strategy_id)
            
            # 清理策略订阅记录
            del self._strategy_subscriptions[strategy_id]
        
        logger.info(f"⏹️ 策略已精确停止: {strategy_id} (类型: {strategy.__class__.__name__})")
        return {
            "status": "stopped",
            "strategy_id": strategy_id,
            "type": strategy.__class__.__name__,
            "positions": dict(strategy.positions)
        }
    
    async def add_subscription(self, stock_code: str, strategy_id: str):
        """
        添加策略订阅 - 双重数据结构保证精确控制
        
        优化点:
        1. 同时维护策略->股票 和 股票->策略 两个映射
        2. 确保策略停止时能精确清理
        """
        # 1. 检查是否已订阅
        if (strategy_id in self._strategy_subscriptions and 
            stock_code in self._strategy_subscriptions[strategy_id]):
            return
        
        # 2. 如果是该股票的第一个策略，真实订阅
        first_subscriber = len(self._stock_subscribers[stock_code]) == 0
        
        # 3. 添加到数据结构
        if strategy_id not in self._strategy_subscriptions:
            self._strategy_subscriptions[strategy_id] = []
        
        if stock_code not in self._strategy_subscriptions[strategy_id]:
            self._strategy_subscriptions[strategy_id].append(stock_code)
        
        if strategy_id not in self._stock_subscribers[stock_code]:
            self._stock_subscribers[stock_code].append(strategy_id)
        
        # 4. 如果是第一个订阅者，真实订阅
        if first_subscriber:
            from .qmt_client import qmt_client
            loop = asyncio.get_running_loop()
            await loop.run_in_executor(None, qmt_client.subscribe, stock_code)
            logger.info(f"🔔 首次订阅 {stock_code} - 开始接收行情")
        
        logger.info(
            f"🔔 添加订阅: {stock_code} <- 策略 {strategy_id} "
            f"(当前订阅者: {len(self._stock_subscribers[stock_code])})"
        )
    
    async def remove_subscription(self, stock_code: str, strategy_id: str):
        """
        【精确控制】移除策略订阅 - 基于 strategy_id 和 stock_code 协同
        
        优化点:
        1. 精确移除指定策略对指定股票的订阅
        2. 保持数据结构一致性
        3. 智能清理空订阅
        """
        # 1. 从策略订阅列表移除
        if (strategy_id in self._strategy_subscriptions and 
            stock_code in self._strategy_subscriptions[strategy_id]):
            self._strategy_subscriptions[strategy_id].remove(stock_code)
            
            # 如果策略没有其他订阅了，清理记录
            if not self._strategy_subscriptions[strategy_id]:
                del self._strategy_subscriptions[strategy_id]
        
        # 2. 从股票订阅者列表移除
        if strategy_id in self._stock_subscribers[stock_code]:
            self._stock_subscribers[stock_code].remove(strategy_id)
            
            # 3. 如果没有策略订阅了，清理QMT订阅
            if not self._stock_subscribers[stock_code]:
                del self._stock_subscribers[stock_code]
                logger.info(f"🧹 清理空订阅: {stock_code} (无策略订阅)")
        
        logger.debug(f"🔕 移除订阅: {stock_code} <- 策略 {strategy_id}")
    
    async def on_tick(self, stock_code: str, data: Dict[str, Any]):
        """
        处理行情数据 - 分发给所有订阅该股票的策略
        
        优化点:
        1. 基于 strategy_id 精确分发
        2. 异常隔离，单个策略失败不影响其他策略
        """
        subscribers = self._stock_subscribers.get(stock_code, [])
        
        if not subscribers:
            return
        
        logger.info(f"📡 收到 {stock_code} 行情，分发给 {len(subscribers)} 个策略")
        
        # 并行处理所有订阅策略
        tasks = []
        for strategy_id in subscribers:
            strategy = self._strategies.get(strategy_id)
            if strategy and strategy.is_running:
                tasks.append(self._process_strategy_tick(strategy, data.copy()))
        
        if tasks:
            await asyncio.gather(*tasks, return_exceptions=True)
    
    async def _process_strategy_tick(self, strategy: BaseStrategy, data: Dict[str, Any]):
        """处理单个策略的行情数据 - 异常隔离"""
        try:
            await strategy.on_tick(data)
        except Exception as e:
            logger.error(f"❌ 策略 {strategy.strategy_id} 处理行情失败: {str(e)}", exc_info=True)
            # 【可选】策略异常处理逻辑
            # await self.handle_strategy_error(strategy, e)
    
    def get_strategy(self, strategy_id: str) -> Optional[BaseStrategy]:
        """获取策略实例"""
        return self._strategies.get(strategy_id)
    
    def list_strategies(self) -> Dict[str, Dict[str, Any]]:
        """列出所有策略信息"""
        result = {}
        for sid, strategy in self._strategies.items():
            result[sid] = {
                "type": strategy.__class__.__name__,
                "status": "running" if strategy.is_running else "stopped",
                "positions": dict(strategy.positions),
                "params": strategy.params,
                "created_at": strategy.created_at,
                "subscriptions": list(getattr(strategy, '_subscribed_stocks', []))
            }
        return result
    
    async def cleanup(self):
        """清理所有资源"""
        logger.info("🧹 开始清理策略管理器资源...")
        
        # 停止所有策略
        for sid in list(self._strategies.keys()):
            await self.remove_strategy(sid)
        
        logger.info("✅ 策略管理器资源已清理完成")

# 导出单例实例
strategy_manager = StrategyManager()